package ldh.im.fxgui.controller;

import javafx.beans.InvalidationListener;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Popup;
import ldh.im.ImConfig;
import ldh.im.fxbase.dao.ImSessionDao;
import ldh.im.fxbase.dao.ImUserDao;
import ldh.im.fxbase.data.event.AvInvite;
import ldh.im.fxbase.data.pojo.ImSession;
import ldh.im.fxbase.data.pojo.ImUser;
import ldh.im.fxbase.data.pojo.status.ImSessionStatus;
import ldh.im.fxbase.emoji.ImageCache;
import ldh.im.fxbase.data.event.EventBusFactory;
import ldh.im.fxbase.restart4j.ApplicationRestart;
import ldh.im.fxbase.service.ImSessionService;
import ldh.im.fxbase.util.*;
import ldh.im.fxgui.component.ImStage;
import ldh.im.fxgui.controller.sub.FeedbackController;
import ldh.im.fxgui.controller.sub.UserHeaderIconController;
import ldh.im.fxgui.stage.AudioStage;
import ldh.im.fxgui.stage.VideoStage;
import ldh.im.fxgui.util.UiUtil;
import ldh.im.util.Sets;
import ldh.rpc.cache.CacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.text.html.Option;
import java.net.URL;
import java.util.Date;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.function.Consumer;

/**
 * 主界面
 */
public class MainController implements Initializable {

    private static final Logger LOGGER = LoggerFactory.getLogger(MainController.class);

    @FXML private Label userIconLabel;
    @FXML private ImageView headIcon;
    @FXML private StackPane contentPane;
    @FXML private Pane leftPane;
    @FXML private Node defaultIcon;
    @FXML private Node workbenchIcon;
    @FXML private Label settingLabel;
    @FXML private Label hotMessageTotalLabel;
    @FXML private Pane hotMessageTotalPane;

    // 显示当前那个面板：消息面板 or 用户面板
    private Popup popup = new Popup();
    private Pane settingPopupPane = null;
    private Pane userHeaderIconPane = null;
    private ImStage fileStage = null;
    private ImStage feedStage = null; // 反馈Stage

    private StringProperty currentProperty = new SimpleStringProperty("");
    private IntegerProperty hotMessageNumProperty = new SimpleIntegerProperty(0);

    private RegionUtil.FxmlBean<Pane, UserTreeController> userTreeFxmlBean = null;
    private RegionUtil.FxmlBean<Pane, MessageSessionController> messageSessionFxmlBean = null;
    private RegionUtil.FxmlBean<Pane, CollectController> collectFxmlBean = null;
    private RegionUtil.FxmlBean<Pane, SettingController> settingFxmlBean = null;
    private RegionUtil.FxmlBean<Pane, WorkbenchController> workFxmlBean = null;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        StageUtil.setRoot(contentPane);
        ImHotMessageSingleton.getInstance().bindHotMessage(0L, hotMessageNumProperty);

        popup.setAutoHide(true);

        currentProperty.addListener((InvalidationListener) l -> {
            leftPane.getChildren().forEach(node -> {
                if (node instanceof StackPane) {
                    cleanActiveAndAddDefault(defaultIcon, "MessagePane");
                    return;
                }
                Node icon = node;
                if (node instanceof Label) {
                    icon = ((Label) node).getGraphic();
                }
                Object obj = icon.getUserData();
                if (obj == null) {
                    return;
                }
                if (!obj.toString().equals("MessagePane")) {
                    UiUtil.setSendMessageHandler(null);
                }
                cleanActiveAndAddDefault(icon, obj.toString());
            });
        });

        hotMessageTotalPane.visibleProperty().bind(hotMessageNumProperty.greaterThan(0));
        hotMessageTotalLabel.textProperty().bind(hotMessageNumProperty.asString());
//        hotMessageTotalPane.setVisible(false);
    }

    /**
     * 显示用户管理信息
     *
     * @param mouseEvent
     */
    @FXML
    private void showUserPane(MouseEvent mouseEvent) {
        String ownerData = ((Node) mouseEvent.getSource()).getUserData().toString();
        if (currentProperty.get().equals(ownerData)) return;
        currentProperty.set(ownerData);
        if (this.userTreeFxmlBean == null) {
            this.userTreeFxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/UserTreePage.fxml"));
            userTreeFxmlBean.getController().setMainController(this);
        }
        UiUtil.setSendMessageHandler(null);
        showPane(userTreeFxmlBean, null, null, null, null);
    }

    /**
     * 显示消息面板
     *
     * @param mouseEvent
     */
    @FXML
    public void showMessagePane(MouseEvent mouseEvent) {
        if(mouseEvent != null) {
            showMessagePane(Optional.of(mouseEvent), Optional.empty());
        } else {
            showMessagePane(Optional.empty(), Optional.empty());
        }

    }

    /**
     * 显示收藏管理信息
     *
     * @param mouseEvent
     */
    @FXML
    private void showCollectPane(MouseEvent mouseEvent) {
        String ownerData = ((Node) mouseEvent.getSource()).getUserData().toString();
        if (currentProperty.get().equals(ownerData)) return;
        currentProperty.set(ownerData);
        if (this.collectFxmlBean == null) {
            collectFxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/CollectPage.fxml"));
        }
        UiUtil.setSendMessageHandler(null);
        showPane(null, null, collectFxmlBean, null, null);
    }

    /**
     * 显示文件管理信息
     *
     * @param mouseEvent
     */
    @FXML
    private void showFilePane(MouseEvent mouseEvent) {
        String ownerData = ((Node) mouseEvent.getSource()).getUserData().toString();
        if (currentProperty.get().equals(ownerData)) return;
        currentProperty.set(ownerData);
        if (fileStage == null) {
            fileStage = new ImStage(880, 500);
            fileStage.getRoot().getStyleClass().add("file-page");

            fileStage.getCurrentScene().getStylesheets().add(this.getClass().getResource("/css/file.css").toExternalForm());
            RegionUtil.FxmlBean<Node, FileController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/FilePage.fxml"));

            fileStage.setTitle("聊天文件");
            fileStage.setContent(fxmlBean.getNode());
            fileStage.setOnCloseRequest(ee -> {
                LOGGER.debug("newStage do close event！");
                fileStage = null;
            });
        }

        fileStage.show();
        fileStage.toFront();
    }

    @FXML
    private void showSettingPane(MouseEvent mouseEvent) {
        String ownerData = ((Node) mouseEvent.getSource()).getUserData().toString();
        if (currentProperty.get().equals(ownerData)) return;
        currentProperty.set(ownerData);
        if (settingFxmlBean == null) {
            settingFxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/SettingPane.fxml"));
        }
        UiUtil.setSendMessageHandler(null);
        showPane(null, null, null, settingFxmlBean, null);
    }

    @FXML
    private void showWorkbenchPane(MouseEvent mouseEvent) {
        String ownerData = ((Node) mouseEvent.getSource()).getUserData().toString();
        if (currentProperty.get().equals(ownerData)) return;
        currentProperty.set(ownerData);
        cleanActiveAndAddDefault(workbenchIcon, "WorkbenchPane");
        workFxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/WorkbenchPage.fxml"));
        showPane(null, null, null, null, workFxmlBean);
        Node pane = workFxmlBean.getNode();
        UiUtil.setSendMessageHandler(null);
    }

    @FXML
    private void showOtherPop(MouseEvent mouseEvent) {
        if (settingPopupPane == null) {
            settingPopupPane = createOtherPane();
        }
        popup.getContent().clear();
        popup.getContent().add(settingPopupPane);
        double x = RegionUtil.calcAnchorX(leftPane, PopupPos.up_east, settingPopupPane);
        double y = RegionUtil.calcAnchorY(settingLabel, PopupPos.up_east, settingPopupPane);
        popup.show(settingLabel.getScene().getWindow(), x, y);
    }

    @FXML
    private void showUserHeaderImagePane(MouseEvent mouseEvent) {
        if (userHeaderIconPane == null) {
            userHeaderIconPane = createUserPane();
        }
        popup.getContent().clear();
        popup.getContent().add(userHeaderIconPane);
        double x = RegionUtil.calcAnchorX(userIconLabel, PopupPos.down_east, userHeaderIconPane) + userIconLabel.getWidth();
        double y = RegionUtil.calcAnchorY(userIconLabel, PopupPos.down_east, userHeaderIconPane);
        popup.show(userIconLabel.getScene().getWindow(), x, y);
    }

    public void switchUserMessage(ImUser imUser, Consumer consumer) {
        ImSessionDao imSessionDao = BeanFactory.getInstance().getBean(ImSessionDao.class);
        ImSessionService imSessionService = BeanFactory.getInstance().getBean(ImSessionService.class);

//        showMessagePane(null);
        RegionUtil.FxmlBean<Pane, MessageSessionController> fxmlBean = getCacheFxmlBean("Main-MessagePane");
        ThreadPoolUtil.submit(() -> {
            try {
                CacheService cacheService = RpcUtil.getRpcBootstrap().getRpcConfig().getCacheService();
                String userId = (String) cacheService.getCache(ImConfig.LOGIN_USER_ID);
                ImSession imSession = imSessionDao.getByUserId(userId, userId, imUser.getUserId());
                if (imSession == null) {
                    imSession = imSessionService.createSession(userId, imUser);
                }
                if (imSession.getStatus() == ImSessionStatus.disable) {
                    imSession.setStatus(ImSessionStatus.enable);
                    imSession.setUpdateTime(new Date());
                    imSessionDao.updateSession(imSession);
                }
                ImSession session = imSession;
                FxThreadUtil.runLater(() -> {
                    try {
                        showMessagePane(Optional.empty(), Optional.of(session));
                        if (consumer != null) consumer.accept(null);
                    } catch (Exception e) {
                        LOGGER.error("switch session error", e);
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

    }

    public void switchMessageSession(ImSession imSession) {
        boolean isCurrentMessagePane = showMessagePane(Optional.empty(), Optional.of(imSession));
        if (!isCurrentMessagePane) return;
        if (this.messageSessionFxmlBean == null) return;
        ThreadPoolUtil.submit(() -> {
            FxThreadUtil.runLater(() -> {
                messageSessionFxmlBean.getController().switchSession(imSession);
            });
        });
    }

    public void webRtcInvite(AvInvite avInvite) {
        if (avInvite.isAudio()) {
            FxThreadUtil.runLater(()->{
                AudioStage audioStage = new AudioStage("audioRoomStage");
                audioStage.doOpenAudioPane(avInvite.getFromUserId(), avInvite.getGroupId(), Sets.asSet(avInvite.getUserId(), avInvite.getFromUserId()));
            });
        } else {
            FxThreadUtil.runLater(()->{
                VideoStage videoStage = new VideoStage("videoRoomStage");
                videoStage.doOpenVideoPane(avInvite.getFromUserId(), avInvite.getGroupId(),
                        Sets.asSet(avInvite.getUserId(), avInvite.getFromUserId()));
            });
        }
    }

    public void popupHide() {
        popup.hide();
    }

    public <N, C> RegionUtil.FxmlBean<N, C> getCacheFxmlBean(String key) {
        RegionUtil.FxmlBean fxmlBean = SoftMapUtil.getCache(key);
        if (fxmlBean == null) return null;
        return fxmlBean;
    }

    private void cleanActiveAndAddDefault(Node node, String userData) {
        if (node.getStyleClass().contains("active")) {
            node.getStyleClass().remove("active");
            node.getStyleClass().add("default-icon");
        }
        if (currentProperty.get().equals(userData)) {
            node.getStyleClass().add("active");
            node.getStyleClass().remove("default-icon");
        }
    }

    public void setHeadIcon(String icon) {
        String imageURl = ImageCache.getInstance().getImagePath(icon);
        if (imageURl != null) {
            headIcon.setImage(new Image(imageURl));
        } else {
            Image image = new Image(this.getClass().getResource("/imgs/head.jpg").toExternalForm());
            headIcon.setImage(image);
        }
    }

    public void loadHeadIcon() {
        ThreadPoolUtil.submit(() -> {
            ExceptionUtil.catchException(() -> {
                ImUserDao imUserDao = BeanFactory.getInstance().getBean(ImUserDao.class);
                CacheService cacheService = RpcUtil.getRpcBootstrap().getRpcConfig().getCacheService();
                String userId = (String) cacheService.getCache(ImConfig.LOGIN_USER_ID);
                ImUser imUser = imUserDao.getUserById(userId);

                String icon = imUser.getHeadImg();
                String headIcon = icon == null ? "/imgs/head.jpg" : icon;
                FxThreadUtil.runLater(() -> {
                    setHeadIcon(headIcon);
                });
                return null;
            }, "获取用户图像");
        });
    }

    private VBox createOtherPane() {
        VBox vBox = new VBox();
        vBox.getStyleClass().add("setting-popup-pane");
        Button yjfkBtn = RegionUtil.createButton("意见反馈", this::feedback);
//        Button bfhfBtn = new Button("备份和恢复");
        Button changeUserBtn = RegionUtil.createButton("切换用户", this::changeLoginUser);
        Button settingBtn = RegionUtil.createButton("退出", e -> StageUtil.close());
        vBox.getChildren().addAll(yjfkBtn, changeUserBtn, settingBtn);
        return vBox;
    }

    // 功能反馈
    private void feedback(ActionEvent actionEvent) {
        if (feedStage == null) {
            feedStage = new ImStage();
            feedStage.getCurrentScene().getStylesheets().add(this.getClass().getResource("/css/setting.css").toExternalForm());
            feedStage.getCurrentScene().getStylesheets().add(this.getClass().getResource("/css/table.css").toExternalForm());
            RegionUtil.FxmlBean<Node, FeedbackController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/sub/FeedbackPage.fxml"));
            fxmlBean.getController().setImStage(feedStage);
            feedStage.setContent(fxmlBean.getNode());
            feedStage.setTitle(ImConfig.IM_NAME + "意见反馈");
            feedStage.setOnCloseRequest(ee -> {
                LOGGER.debug("feedStage do close event！");
                feedStage = null;
            });
        }
        feedStage.show();
    }

    private GridPane createUserPane() {
        RegionUtil.FxmlBean<GridPane, UserHeaderIconController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/sub/UserHeaderIconPane.fxml"));
        fxmlBean.getController().setImUser(UiUtil.getLoginImUser());
        fxmlBean.getController().setMainController(UiUtil.getMainController());
        return fxmlBean.getNode();
    }

    private void changeLoginUser(ActionEvent actionEvent) {
        final ApplicationRestart appRestart = ApplicationRestart.builder()
                .beforeNewProcessCreated(() -> LOGGER.info("Im Application creating!"))
                .beforeCurrentProcessTerminated(() -> LOGGER.info("Im Application will be terminated"))
                .build();
        appRestart.restartApp();
    }

    private Node getCachePane(String key) {
        RegionUtil.FxmlBean<Pane, ?> fxmlBean = SoftMapUtil.getCache(key);
        if (fxmlBean == null) return null;
        // todo 缓存会导致组件出现异常，界面就异常了。后续找方法是否能解决
        return fxmlBean.getNode();
//        return null;
    }

    private boolean showMessagePane(Optional<MouseEvent> mouseEventOption, Optional<ImSession> sessionOption) {
        String ownerData = "MessagePane";
        if (currentProperty.get().equals(ownerData)) return true;
        if (mouseEventOption.isPresent()) {
            ownerData = ((Node) mouseEventOption.get().getSource()).getUserData().toString();
            if (currentProperty.get().equals(ownerData)) return true;
        }
        currentProperty.set(ownerData);
        if (messageSessionFxmlBean == null) {
            messageSessionFxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/MessageSessionPane.fxml"));
            EventBusFactory.getInstance().register(messageSessionFxmlBean.getController());
            messageSessionFxmlBean.getController().setMainController(this);
            messageSessionFxmlBean.getController().loadMessageSessionData(sessionOption);
        } else {
            messageSessionFxmlBean.getController().loadLastedMessage(sessionOption);
        }
        showPane(null, messageSessionFxmlBean, null, null, null);
        loadHeadIcon();
        return false;
    }


    private void showPane(RegionUtil.FxmlBean<Pane, UserTreeController> userTreeFxmlBean,
                          RegionUtil.FxmlBean<Pane, MessageSessionController> messageSessionFxmlBean,
                          RegionUtil.FxmlBean<Pane, CollectController> collectFxmlBean,
                          RegionUtil.FxmlBean<Pane, SettingController> settingFxmlBean,
                          RegionUtil.FxmlBean<Pane, WorkbenchController> workFxmlBean) {
        nullAllPane();
        if (userTreeFxmlBean != null) {
            this.userTreeFxmlBean = userTreeFxmlBean;
            this.userTreeFxmlBean.getController().setMainController(this);
            contentPane.getChildren().setAll(userTreeFxmlBean.getNode());
        }
        if (messageSessionFxmlBean != null) {
            this.messageSessionFxmlBean = messageSessionFxmlBean;
            this.messageSessionFxmlBean.getController().setMainController(this);
            contentPane.getChildren().setAll(messageSessionFxmlBean.getNode());
        }
        if (collectFxmlBean != null) {
            this.collectFxmlBean = collectFxmlBean;
            contentPane.getChildren().setAll(collectFxmlBean.getNode());
        }
        if (settingFxmlBean != null) {
            this.settingFxmlBean = settingFxmlBean;
            contentPane.getChildren().setAll(settingFxmlBean.getNode());
        }
        if (workFxmlBean != null) {
            this.workFxmlBean = workFxmlBean;
            contentPane.getChildren().setAll(workFxmlBean.getNode());
        }
    }

    private void nullAllPane() {
        contentPane.getChildren().clear();
        if (userTreeFxmlBean != null) {
            this.userTreeFxmlBean.getController().setMainController(null);
            this.userTreeFxmlBean = null;
        }
        if (messageSessionFxmlBean != null) {
            this.messageSessionFxmlBean.getController().setMainController(null);
            this.messageSessionFxmlBean = null;
        }
        if (collectFxmlBean != null) {
            this.collectFxmlBean = null;
        }
        if (settingFxmlBean != null) {
            this.settingFxmlBean.getController().setStage(null);
            this.settingFxmlBean = null;
        }
        if (workFxmlBean != null) {
            this.workFxmlBean = null;
        }
    }

}
